import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.ArrayList;
import java.util.LinkedList;

public class DynamicPagingPanel extends JPanel {
    // 页表项定义
    class PageTableEntry {
        int pageNo;
        boolean isPresent;
        int frameNo = -1;
        boolean isModified;
        int diskLocation;

        public PageTableEntry(int pageNo, int diskLocation) {
            this.pageNo = pageNo;
            this.diskLocation = diskLocation;
        }
    }

    // 内存块定义（简化版：总共8个块）
    class Frame {
        int frameNo;
        PageTableEntry page;
        boolean isFree = true;

        public Frame(int frameNo) {
            this.frameNo = frameNo;
        }
    }

    // 系统参数
    private static final int TOTAL_FRAMES = 4; // 总内存块数（8KB内存）
    private static final int FRAME_SIZE = 1024; // 每块1KB
    private static final int JOB_FRAMES = 4;    // 作业分配到的内存块数

    // 数据结构
    private LinkedList<Frame> allFrames = new LinkedList<>(); // 所有内存块
    private LinkedList<Frame> jobFrames = new LinkedList<>(); // 作业独占的内存块（FIFO队列）
    private java.util.List<PageTableEntry> pageTable = new ArrayList<>(); // 页表

    // GUI组件
    private DefaultTableModel tableModel;
    private JTextArea logArea;
    private JTextField pageField, offsetField;

    public DynamicPagingPanel() {
        setLayout(new BorderLayout());
        initMemory();
        initPageTable();
        initUI();
    }

    private void initMemory() {
        // 初始化4个物理内存块（编号0-3）
        for (int i = 0; i < TOTAL_FRAMES; i++) {
            allFrames.add(new Frame(i));
        }
        // 为作业分配全部内存块（局部置换范围）
        jobFrames.addAll(allFrames);
    }

    private void initPageTable() {
        // 初始化页表（页号0-6）
        int[] diskLocations = {010, 012, 013, 021, 022, 023, 125};
        for (int i = 0; i < 7; i++) {
            pageTable.add(new PageTableEntry(i, diskLocations[i]));
        }

        // 预装入前4个页面（映射到实际存在的块0-3）
        pageTable.get(0).isPresent = true; pageTable.get(0).frameNo = 0; // 页号0 -> 块0
        pageTable.get(1).isPresent = true; pageTable.get(1).frameNo = 1; // 页号1 -> 块1
        pageTable.get(2).isPresent = true; pageTable.get(2).frameNo = 2; // 页号2 -> 块2
        pageTable.get(3).isPresent = true; pageTable.get(3).frameNo = 3; // 页号3 -> 块3

        // 关联内存块与页面
        jobFrames.get(0).page = pageTable.get(0); jobFrames.get(0).isFree = false;
        jobFrames.get(1).page = pageTable.get(1); jobFrames.get(1).isFree = false;
        jobFrames.get(2).page = pageTable.get(2); jobFrames.get(2).isFree = false;
        jobFrames.get(3).page = pageTable.get(3); jobFrames.get(3).isFree = false;
    }
    private void initUI() {
        // 页表显示
        String[] columns = {"页号", "存在", "块号", "修改", "磁盘位置"};
        tableModel = new DefaultTableModel(columns, 0);
        JTable table = new JTable(tableModel);
        updateTableModel();

        // 输入面板
        JPanel inputPanel = new JPanel();
        pageField = new JTextField(3);
        offsetField = new JTextField(5);
        JButton execButton = new JButton("执行指令");
        JButton resetButton = new JButton("重置");

        execButton.addActionListener(e -> executeInstruction());
        resetButton.addActionListener(e -> resetSystem());

        inputPanel.add(new JLabel("页号:"));
        inputPanel.add(pageField);
        inputPanel.add(new JLabel("页内地址:"));
        inputPanel.add(offsetField);
        inputPanel.add(execButton);
        inputPanel.add(resetButton);

        // 日志区域
        logArea = new JTextArea(10, 50);
        logArea.setEditable(false);

        // 内存状态可视化
        JPanel memPanel = new JPanel(new GridLayout(1, JOB_FRAMES));
        for (Frame frame : jobFrames) {
            JLabel label = new JLabel("块" + frame.frameNo, SwingConstants.CENTER);
            label.setOpaque(true);
            label.setBackground(frame.isFree ? Color.GREEN : Color.ORANGE);
            label.setBorder(BorderFactory.createLineBorder(Color.BLACK));
            memPanel.add(label);
        }

        // 布局
        add(inputPanel, BorderLayout.NORTH);
        add(new JScrollPane(table), BorderLayout.CENTER);
        add(new JScrollPane(logArea), BorderLayout.SOUTH);
    }

    private void executeInstruction() {
        try {
            int pageNo = Integer.parseInt(pageField.getText());
            int offset = Integer.parseInt(offsetField.getText());

            if (pageNo < 0 || pageNo >= pageTable.size()) {
                logArea.append("错误：页号无效！\n");
                return;
            }
            if (offset < 0 || offset >= FRAME_SIZE) {
                logArea.append("错误：页内地址超出范围！\n");
                return;
            }

            PageTableEntry entry = pageTable.get(pageNo);
            if (entry.isPresent) {
                int physicalAddr = (entry.frameNo << 10) | offset;
                logArea.append(String.format(
                        "物理地址=%d (块号=%d << 10 | 偏移=%d)\n",
                        physicalAddr, entry.frameNo, offset
                ));
            } else {
                handlePageFault(entry);
                int physicalAddr = (entry.frameNo << 10) | offset;
                logArea.append(String.format(
                        "缺页中断！页面%d调入内存块%d，物理地址：%d\n",
                        pageNo, entry.frameNo, physicalAddr));
            }
            updateTableModel();
        } catch (NumberFormatException e) {
            logArea.append("错误：请输入有效数字！\n");
        }
    }
    private void handlePageFault(PageTableEntry entry) {
        // 查找空闲块（在jobFrames中）
        Frame targetFrame = null;
        for (Frame frame : jobFrames) {
            if (frame.isFree) {
                targetFrame = frame;
                break;
            }
        }

        // 无空闲块则置换
        if (targetFrame == null) {
            targetFrame = jobFrames.pollFirst(); // FIFO选择牺牲页
            targetFrame.page.isPresent = false;  // 淘汰旧页
            logArea.append(String.format("淘汰页面%d（内存块%d）\n",
                    targetFrame.page.pageNo, targetFrame.frameNo));
            jobFrames.addLast(targetFrame);      // 重新加入队列尾部
        }

        // 装入新页
        entry.isPresent = true;
        entry.frameNo = targetFrame.frameNo;     // 关键：分配正确的块号！
        targetFrame.page = entry;
        targetFrame.isFree = false;
    }
    private void updateTableModel() {
        tableModel.setRowCount(0);
        for (PageTableEntry entry : pageTable) {
            tableModel.addRow(new Object[]{
                    entry.pageNo,
                    entry.isPresent ? "是" : "否",
                    entry.isPresent ? entry.frameNo : "-",
                    entry.isModified ? "是" : "否",
                    String.format("%03o", entry.diskLocation) // 八进制显示
            });
        }
    }

    private void resetSystem() {
        jobFrames.clear();
        pageTable.clear();
        initMemory();
        initPageTable();
        updateTableModel();
        logArea.setText("系统已重置！\n");
    }
}